package com.google.code.p.restrpc.mon.web.client;

import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;

import com.google.code.p.restrpc.AsyncRpcResult;
import com.google.code.p.restrpc.RpcOptions;
import com.google.code.p.restrpc.client.RpcOptionsFactory;
import com.google.code.p.restrpc.client.cache.ServiceMetadata;
import com.google.code.p.restrpc.client.cache.ServiceMetadataRepository;
import com.google.code.p.restrpc.client.cache.ServiceMetadataVisitor;
import com.google.code.p.restrpc.client.cluster.FailureRecoveryStrategyManager;
import com.google.code.p.restrpc.client.loadbalance.LoadBalanceStrategyManager;
import com.google.code.p.restrpc.client.proxy.RpcProxyFactory;
import com.google.code.p.restrpc.client.proxy.RpcProxyMetadata;
import com.google.code.p.restrpc.client.proxy.RpcProxyMetadataTracker;
import com.google.code.p.restrpc.http.RestTemplate;

public class ClientMonitor {
    
    public static final Map EMPTY_MAP = new HashMap(0);
    
    public ClientMonitor() {
    }
    
    public Map restRpcProperties(Map parameters) {
        Properties properties = new Properties();
        try {
            InputStream is = RpcOptionsFactory.class.getClassLoader()
                                                    .getResourceAsStream("/restrpc.client.properties");
            if (is != null) {
                properties.load(is);
            }
        }
        catch (Exception e) {
        }
        Map result = new HashMap();
        result.putAll(properties);
        return result;
    }
    
    public Map restRpcOptions(Map parameters) {
        return convertRpcOptionsToMap(RpcOptionsFactory.getInstance());
    }
    
    private Map convertRpcOptionsToMap(RpcOptions options) {
        if (options == null) {
            return EMPTY_MAP;
        }
        Map result = new HashMap();
        result.put(RpcOptions.RESTRPC_TRANSFER_FORMAT,
                   options.getTransferFormat());
        result.put(RpcOptions.RESTRPC_LOADBALANCE_STRATEGY,
                   options.getLoadBalance());
        result.put(RpcOptions.RESTRPC_FAILURERECOVERY_STRATEGY,
                   options.getFailureRecovery());
        result.put(RpcOptions.RESTRPC_CLIENT_RETRIES,
                   options.getNumberOfRetries());
        result.put(RpcOptions.RESTRPC_CLIENT_HEARTBEAT, options.getHeartbeat());
        result.put(RpcOptions.RESTRPC_DIRECTORY_SERVICE_URL,
                   options.getDirectoryServiceUrl());
        return result;
    }
    
    public Map httpClientProperties(Map parameters) {
        Properties properties = new Properties();
        try {
            InputStream is = RestTemplate.class.getClassLoader()
                                               .getResourceAsStream("/http.client.properties");
            if (is != null) {
                properties.load(is);
            }
        }
        catch (Exception e) {
        }
        Map result = new HashMap();
        result.putAll(properties);
        return result;
    }
    
    public Map failureStrategy(Map parameters) {
        Properties properties = new Properties();
        try {
            InputStream is = FailureRecoveryStrategyManager.class.getResourceAsStream("/META-INF/configuration/failurerecovery.strategy.properties");
            if (is != null) {
                properties.load(is);
            }
        }
        catch (Exception e) {
        }
        Map result = new HashMap();
        result.putAll(properties);
        return result;
    }
    
    public Map loadbalanceStrategy(Map parameters) {
        Properties properties = new Properties();
        try {
            InputStream is = LoadBalanceStrategyManager.class.getResourceAsStream("/META-INF/configuration/loadbalance.strategy.properties");
            if (is != null) {
                properties.load(is);
            }
        }
        catch (Exception e) {
        }
        Map result = new HashMap();
        result.putAll(properties);
        return result;
    }
    
    public Map rpcProxies(Map parameters) {
        Map<String, SoftReference<RpcProxyMetadata>> rpcRroxyRefs = RpcProxyMetadataTracker.getInstance()
                                                                                           .getRpcProxyMetadatas();
        
        Map result = new HashMap();
        if (rpcRroxyRefs == null) {
            return result;
        }
        
        for (Iterator<Entry<String, SoftReference<RpcProxyMetadata>>> iterator = rpcRroxyRefs.entrySet()
                                                                                             .iterator(); iterator.hasNext();) {
            Entry<String, SoftReference<RpcProxyMetadata>> entry = iterator.next();
            SoftReference<RpcProxyMetadata> ref = entry.getValue();
            if (ref != null && ref.get() != null) {
                RpcProxyMetadata metadata = ref.get();
                Map item = new HashMap();
                item.put("createDateTime", metadata.getCreateDateTime());
                item.put("cacheSize", "0");
                if (metadata.getServiceMetadataRepository() != null) {
                    item.put("cacheSize",
                             metadata.getServiceMetadataRepository().size());
                }
                result.put(entry.getKey(), item);
            }
        }
        
        return result;
    }
    
    public Map rpcProxyDetail(Map parameters) {
        String[] ids = (String[]) parameters.get("id");
        if (ids == null || ids.length == 0) {
            return EMPTY_MAP;
        }
        String id = ids[0];
        if (StringUtils.isEmpty(id)) {
            return EMPTY_MAP;
        }
        
        SoftReference<RpcProxyMetadata> entryRef = RpcProxyMetadataTracker.getInstance()
                                                                          .getRpcProxyMetadatas()
                                                                          .get(id);
        if (entryRef == null) {
            return EMPTY_MAP;
        }
        
        RpcProxyMetadata rpcProxyMetadata = entryRef.get();
        
        if (rpcProxyMetadata == null) {
            return EMPTY_MAP;
        }
        
        Map result = new HashMap();
        
        result.put("rpcOptions",
                   convertRpcOptionsToMap(rpcProxyMetadata.getRpcOptions()));
        ServiceMetadataRepository serviceMetadataRepository = rpcProxyMetadata.getServiceMetadataRepository();
        if (serviceMetadataRepository != null) {
            final List<ServiceMetadata> metadatas = new ArrayList<ServiceMetadata>();
            serviceMetadataRepository.accept(new ServiceMetadataVisitor() {
                
                public void visit(ServiceMetadata serviceMetadata) {
                    metadatas.add(serviceMetadata);
                }
            });
            result.put("metadatas", metadatas);
        }
        
        return result;
    }
     
}
